﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using LowLevelGraphics.Extensions;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// 
    /// </summary>
    public delegate Color NeighbouringDelegate(UnsafeBitmap bitmap, Pixel pixel);

    //TODO: test
    /// <summary>
    /// Neighbouring is used to define neighbouring pixels.
    /// This might also be used to examine patterns.
    /// </summary>
    public class Neighbouring : BaseImageFilter
    {
        protected Neighbours m_aNeighbour = new Neighbours();
        protected NeighbouringDelegate m_NeighbouringDelegate = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="Neighbouring"/> class.
        /// </summary>
        public Neighbouring()           
        {
            this.m_NeighbouringDelegate = new NeighbouringDelegate(NeighbouringDefaultDelegateSignatur);
            this.m_aNeighbour = new Neighbours() { new Neighbour(3, 3), new Neighbour(-3, -3) };
            this.m_aNeighbour = new Neighbours() { new Neighbour(-3, 3), new Neighbour(3, -3) };
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Neighbouring"/> class.
        /// </summary>
        /// <param name="_neighbouringDelegate">The _neighbouring delegate.</param>
        /// <param name="_aNeighbour">The _a neighbour.</param>
        public Neighbouring(NeighbouringDelegate _neighbouringDelegate, Neighbours _aNeighbour)
        {
            m_aNeighbour = _aNeighbour;
            m_NeighbouringDelegate = _neighbouringDelegate;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Neighbouring"/> class.
        /// </summary>
        /// <param name="_neighbouring">The _neighbouring.</param>
        internal Neighbouring(Neighbouring _neighbouring)
        {
            this.m_NeighbouringDelegate = _neighbouring.m_NeighbouringDelegate;
            this.m_aNeighbour = _neighbouring.m_aNeighbour;
        }

        /// <summary>
        /// Gets or sets the neighbours.
        /// </summary>
        /// <value>The neighbours.</value>
        public Neighbours Neighbours
        {
            get { return m_aNeighbour; }
            set { m_aNeighbour = value; }
        }

        /// <summary>
        /// the neighbouring delegate.
        /// </summary>
        /// <value>The neighbouring delegate.</value>
        public NeighbouringDelegate NeighbouringDelegate
        {
            get { return m_NeighbouringDelegate; }
            set { m_NeighbouringDelegate = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap bitmapCloned = new UnsafeBitmap((UnsafeBitmap)_bitmap.Clone());
            UnsafeBitmap bitmap = _bitmap;
            Pixel.Bitmap = bitmapCloned;
            Pixel.SetNeighbours(this.m_aNeighbour);
            Color color = Color.Transparent;
            foreach (Pixel pixel in
                bitmapCloned.GetPixels(
                    new Rectangle(0, 0, bitmapCloned.Width, bitmapCloned.Height)))
            {
                color = m_NeighbouringDelegate(bitmapCloned, pixel);
                bitmap.SetPixel(pixel.X, pixel.y, color);
            }
            bitmapCloned.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// This is just a simple filter if no parameters are given 
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <param name="pixel"></param>
        /// <returns></returns>
        private Color NeighbouringDefaultDelegateSignatur(UnsafeBitmap _bitmap, Pixel pixel)
        {
            float fSumBrightness = 0;
            Color color = Color.Transparent;
            Neighbour neighbour = null;
            while(pixel.Neighbours.MoveNext())
            {
                neighbour = (Neighbour)pixel.Neighbours.Current;
                color = neighbour.Color;
                fSumBrightness += Color.FromArgb(color.R, 0, 0).GetBrightness();
                fSumBrightness += Color.FromArgb(0, color.G, 0).GetBrightness();
                fSumBrightness += Color.FromArgb(0, 0, color.B).GetBrightness();
            }
            fSumBrightness = fSumBrightness / (m_aNeighbour.Count + 3.0f) * 256;
            int nSumBrightness = (int)fSumBrightness;
            return Color.FromArgb(nSumBrightness, nSumBrightness, nSumBrightness);
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Neighbouring(this);
        }
    }
}
